package com.showSpring.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 切面类
 * 问题： 在注解实现Aop编程中，如果同时使用@AfterReturning与@After,先执行的@After.
 *       所以，通常不一起使用。
 */
@Aspect  // 指定为切面类
@Component // 创建对象
public class TransactionManager {

    //定义切入点表达式
    @Pointcut("execution(* com.itheima.service.impl.AccountServiceImpl.*(..))")
    public void pt(){}

    // 【前置通知】, 表示在执行目标方法之前执行的方法
    @Before("pt()")
    public void before(){
        System.out.println("执行方法之前");
    }
    // 【正常执行,返回通知】, 表示在执行目标方法没有异常执行完毕返回的的方法
    @AfterReturning("pt()")
    public void afterReturning(){
        System.out.println("执行方法正常返回");
    }
    // 【异常通知】, 表示在执行目标方法出现异常之后执行的方法
    @AfterThrowing("pt()")
    public void afterThrowing(){
        System.out.println("执行方法异常输出");
    }
    // 【后置通知】, 表示在执行目标方法之后 必定 会执行的方法
    @After("pt()")
    public void after(){
        System.out.println("执行方法之后必定执行");
    }

    // 【环绕通知】, 将前面四种方法集中到一个方法,推荐使用
    // 此方法返回值，就是最终调用的目标方法的返回值
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp){
        try {
            // 获取方法参数
            Object[] args = pjp.getArgs();
            args[0] = 999;  // 修改了方法的参数

            System.out.println("【环绕前】");
            // 执行目标对象方法
            Object returnValue = pjp.proceed(args);
            System.out.println("【环绕后】");
            return returnValue + ",环绕添加的";
        } catch (Throwable throwable) {
            System.out.println("【环绕异常】");
            throwable.printStackTrace();
            return null;
        } finally {
            System.out.println("【环绕 最终】");
        }
    }
}
